#pragma once
#include <map>
#include <atlstr.h>

#define MAX_VALUE_NAME (1024)

class CComFunRestry
{
public:
	CComFunRestry(void);
	~CComFunRestry(void);

	static DWORD Readkey(__out LPTSTR lpData, __in HKEY hPreKey,
		__in LPCTSTR lpKeyName, __in LPCTSTR lpValueName,
		__in DWORD dwDataLen)
	{
		DWORD dwRetCode = 0;
		HKEY hKey = NULL;
		__try
		{
			dwRetCode = RegOpenKeyEx(hPreKey, lpKeyName, 0,KEY_WOW64_32KEY | KEY_QUERY_VALUE,&hKey);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				__leave;
			}

			dwRetCode = RegQueryValueEx(hKey,lpValueName,NULL,NULL,(LPBYTE)lpData, &dwDataLen);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				__leave;
			}
		}
		__finally
		{
			if (NULL != hKey)
			{
				RegCloseKey(hKey);
				hKey = NULL;
			}
		}
		return dwRetCode;
	}

	static DWORD Createkey(__in HKEY hRootKey, LPCTSTR lpSubKeyPath,
		__in LPCTSTR lpKeyName)
	{
		DWORD dwRetCode = 0;
		HKEY hKey = NULL;
		__try
		{
			dwRetCode = RegOpenKeyEx(hRootKey, lpSubKeyPath, 0, 
				KEY_WOW64_32KEY|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, &hKey);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				__leave;
			}

			HKEY hNewKey = NULL;
			DWORD dwDisposition = 0;
			dwRetCode = RegCreateKeyEx(hKey, lpKeyName, 0,
				NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS|KEY_CREATE_SUB_KEY,
				NULL, &hNewKey, &dwDisposition);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				RegCloseKey(hNewKey);
				__leave;
			}
		}
		__finally
		{
			if (NULL != hKey)
			{
				RegCloseKey(hKey);
				hKey = NULL;
			}
		}
		return dwRetCode;
	}

	static DWORD Removekey(__in HKEY hRootKey, LPCTSTR lpSubKeyPath)
	{
		DWORD dwRetCode = 0;
		HKEY hKey = NULL;
		__try
		{
			dwRetCode = RegDeleteKeyEx(hRootKey, lpSubKeyPath,
				KEY_WOW64_32KEY|KEY_QUERY_VALUE|KEY_CREATE_SUB_KEY, 0);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				__leave;
			}
		}
		__finally
		{
			if (NULL != hKey)
			{
				RegCloseKey(hKey);
				hKey = NULL;
			}
		}
		return dwRetCode;
	}

	static DWORD CreateValue(__in HKEY hRootKey, LPCTSTR lpSubKeyPath,
		__in LPCTSTR lpValueName, __in byte* lpValue,
		__in DWORD dwSize, __in DWORD dwType)
	{
		DWORD dwRetCode = 0;
		HKEY hKey = NULL;
		__try
		{
			dwRetCode = RegOpenKeyEx(hRootKey, lpSubKeyPath, 0, 
				KEY_SET_VALUE, &hKey);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				__leave;
			}

			dwRetCode = RegSetValueEx(hKey, lpValueName, 0,
				dwType, lpValue, dwSize);
			if (ERROR_SUCCESS != dwRetCode)
			{
				SetLastError(dwRetCode);
				__leave;
			}
		}
		__finally
		{
			if (NULL != hKey)
			{
				RegCloseKey(hKey);
				hKey = NULL;
			}
		}
		return dwRetCode;
	}

	static void QueryKey( __in HKEY hPreKey, __in LPCTSTR lpKeyName,
		__out std::map<CString, CString>& mapData) 
	{ 
		TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name 
		DWORD    cchClassName = MAX_PATH;  // size of class string 
		DWORD    cSubKeys=0;               // number of subkeys 
		DWORD    cbMaxSubKey;              // longest subkey size 
		DWORD    cchMaxClass;              // longest class string 
		DWORD    cValues;              // number of values for key 
		DWORD    cchMaxValue;          // longest value name 
		DWORD    cbMaxValueData;       // longest value data 
		DWORD    cbSecurityDescriptor; // size of security descriptor 
		FILETIME ftLastWriteTime;      // last write time 

		DWORD dwRetCode = 0; 

		TCHAR  achValue[MAX_VALUE_NAME] = {}; 
		DWORD cchValue = MAX_VALUE_NAME; 
		HKEY hKey = NULL;

		// Get the class name and the value count. 
		//__try
		do 
		{
			dwRetCode = RegOpenKeyEx( hPreKey,
				lpKeyName,
				0,
				KEY_READ,
				&hKey);
			if(ERROR_SUCCESS != dwRetCode)
			{
				//SetLastError(dwRetCode);
				//__leave;
				break;
			}

			dwRetCode = RegQueryInfoKey(
				hKey,
				achClass,
				&cchClassName,
				NULL,
				&cSubKeys,
				&cbMaxSubKey,
				&cchMaxClass,
				&cValues,
				&cchMaxValue,
				&cbMaxValueData,
				&cbSecurityDescriptor,
				&ftLastWriteTime);

			if (ERROR_SUCCESS != dwRetCode)
			{
				//::SetLastError(dwRetCode);
				//__leave;
				break;
			}

			if (cValues) 
			{
				for (DWORD i=0, dwRetCode=ERROR_SUCCESS; i<cValues; i++) 
				{ 
					cchValue = MAX_VALUE_NAME; 
					achValue[0] = '\0'; 
					dwRetCode = RegEnumValue(hKey, i, 
						achValue, 
						&cchValue, 
						NULL, 
						NULL,
						NULL,
						NULL);

					if (dwRetCode == ERROR_SUCCESS ) 
					{ 
						static TCHAR strData[1024] = {};
						SecureZeroMemory(strData, sizeof(strData) / sizeof(TCHAR));
						DWORD dwRead = Readkey(strData, hKey, L"",
							achValue, 1024 * sizeof(TCHAR));
						mapData.insert(std::make_pair<CString, CString>(achValue, strData));
					}
				}
			}
		}
		//__finally
		while(FALSE);
		{
			if (NULL != hKey)
			{
				RegCloseKey(hKey);
				hKey = NULL;
			}
		}
	}
};
